#pragma once
#include <iostream>
#include <string>
#include <cstdio>
#include <cstring>
#include <cerrno>
#include <unistd.h>
#include <pthread.h>
#include <functional>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/wait.h>

#include "Log.hpp"
#include "InetAddr.hpp"
#include "Common.hpp"

#define RECV_BUFFER_SIZE 1024
#define SEND_BUFFER_SIZE 1024

using namespace My_Log;

namespace My_Socket
{
    class Socket; // 声明
    using SockPtr = std::shared_ptr<Socket>;

    class Socket
    {
    public:
        virtual ~Socket() = default;
        virtual bool SocketOrDie() = 0;
        virtual bool BindOrDie(int port) = 0;
        virtual bool ListenOrDie() = 0;
        virtual SockPtr Accepter(InetAddr *cliaddr) = 0;
        virtual ssize_t Recv(std::string &out) = 0;
        virtual ssize_t Send(const std::string &in) = 0;
        virtual int GetSockfd() = 0;
        virtual void Close() = 0;

        void BuildTcpSocket(int port)
        {
            if(!SocketOrDie()) return; 
            if(!BindOrDie(port)) return;
            if(!ListenOrDie()) return;
        }

    private:
    };

    class TcpSocket : public Socket
    {
    public:
        // 支持传参构造，用于Accepter返回含有指定客户端的文件描述符（_sockfd）的智能指针
        TcpSocket(int sockfd = -1)
            : _sockfd(sockfd), _listensockfd(-1)
        {
        }
        bool SocketOrDie() override
        {
            _listensockfd = ::socket(AF_INET, SOCK_STREAM, 0);
            if (_listensockfd < 0)
            {
                LOG(LogLevel::ERROR) << "socket fail!";
                return false;
            }
            LOG(LogLevel::INFO) << "socket success, listensockfd: " << _listensockfd;
            return true;
        }
        bool BindOrDie(int port) override
        {
            InetAddr addr(port);
            int n = ::bind(_listensockfd, addr.GetSockaddr(), addr.GetSockaddrLen());
            if (n < 0)
            {
                LOG(LogLevel::ERROR) << "bind fail!";
                return false;
            }
            LOG(LogLevel::INFO) << "bind success!";
            return true;
        }
        bool ListenOrDie() override
        {
            int n = ::listen(_listensockfd, 8);
            if (n < 0)
            {
                LOG(LogLevel::ERROR) << "listen fail!";
                return false;
            }
            LOG(LogLevel::INFO) << "listen success!";
            return true;
        }
        SockPtr Accepter(InetAddr *cliaddr) override
        {
            if (cliaddr == nullptr)
            {
                return nullptr;
            }

            // 建立连接
            struct sockaddr_in cliaddr_in;
            socklen_t cliaddrlen;
            _sockfd = ::accept(_listensockfd, CONV(&cliaddr_in), &cliaddrlen);
            if (_sockfd < 0)
            {
                LOG(LogLevel::WARNING) << "accept fail!";
                return nullptr;
            }
            LOG(LogLevel::WARNING) << "accept success!, sockfd: " << _sockfd;

            // 返回参数
            cliaddr->SetAddr(cliaddr_in, cliaddrlen);

            return std::make_shared<TcpSocket>(_sockfd);
        }

        ssize_t Recv(std::string &out)
        {
            char recbuff[RECV_BUFFER_SIZE] = {0};
            int n = ::recv(_sockfd, &recbuff, RECV_BUFFER_SIZE - 1, 0);
            if (n < 0)
            {
                out = std::string();
                return n;
            }
            recbuff[n] = 0;
            out = recbuff;
            return n;
        }

        ssize_t Send(const std::string &in)
        {
            return ::send(_sockfd, in.c_str(), in.size(), 0);
        }

        void Close() override
        {
            if (_sockfd == -1)
                return;
            ::close(_sockfd);
        }

        int GetSockfd() override { return _sockfd; }
        ~TcpSocket() {}

    private:
        int _sockfd;       // accept返回的套接字用于recv和send
        int _listensockfd; // 监听套接字
    };
}